/***************************************************************************
 *cr
 *cr            (C) Copyright 1995-2019 The Board of Trustees of the
 *cr                        University of Illinois
 *cr                         All Rights Reserved
 *cr
 ***************************************************************************/

/***************************************************************************
 * RCS INFORMATION:
 *
 *      $RCSfile: MaterialFltkMenu.C,v $
 *      $Author: johns $        $Locker:  $             $State: Exp $
 *      $Revision: 1.30 $      $Date: 2019/01/17 21:21:00 $
 *
 ***************************************************************************
 * DESCRIPTION:
 *   Material properties GUI form
 ***************************************************************************/

// generated by Fast Light User Interface Designer (fluid) version 1.0100

#include "FL/Fl_Value_Slider.H"
#include "FL/Fl_Hold_Browser.H"
#include "FL/Fl_Button.H"
#include "FL/Fl_Input.H"
#include "FL/forms.H"

#include "MaterialFltkMenu.h"
#include "MaterialList.h"
#include "CmdMaterial.h"
#include "CommandQueue.h"
#include "VMDApp.h"

void MaterialFltkMenu::slider_cb(Fl_Widget *w, void *v) {
  MaterialFltkMenu *self = (MaterialFltkMenu *)v;
  int matprop;
  if (w == self->ambient) {
    matprop = MAT_AMBIENT; 
  } else if (w == self->diffuse ) {
    matprop = MAT_DIFFUSE; 
  } else if (w == self->specular) {
    matprop = MAT_SPECULAR; 
  } else if (w == self->shininess) {
    matprop = MAT_SHININESS; 
  } else if (w == self->mirror) {
    matprop = MAT_MIRROR; 
  } else if (w == self->opacity) {
    matprop = MAT_OPACITY; 
  } else if (w == self->outline) {
    matprop = MAT_OUTLINE; 
  } else if (w == self->outlinewidth) {
    matprop = MAT_OUTLINEWIDTH; 
  } else if (w == self->transmode) {
    matprop = MAT_TRANSMODE; 
  } else {
    return;
  } 
  self->app->material_change(
    self->app->materialList->material_name(self->curmat), matprop, 
         (matprop == MAT_TRANSMODE) ? float(((Fl_Check_Button *)w)->value()) : float(((Fl_Slider *)w)->value()));
}

void MaterialFltkMenu::createnew_cb(Fl_Widget *w, void *v) {
  MaterialFltkMenu *self = (MaterialFltkMenu *)v;
  MaterialList *mlist = self->app->materialList;
  self->app->material_add(NULL, mlist->material_name(self->curmat));
}

void MaterialFltkMenu::delete_cb(Fl_Widget *w, void *v) {
  MaterialFltkMenu *self = (MaterialFltkMenu *)v;
  self->app->material_delete(
      self->app->materialList->material_name(self->curmat));
}

void MaterialFltkMenu::default_cb(Fl_Widget *, void *v) {
  MaterialFltkMenu *self = (MaterialFltkMenu *)v;
  self->app->material_restore_default(self->curmat);
}

void MaterialFltkMenu::browser_cb(Fl_Widget *w, void *v) {
  MaterialFltkMenu *self = (MaterialFltkMenu *)v;
  self->curmat = ((Fl_Hold_Browser *)w)->value()-1;
  self->set_sliders();
}

void MaterialFltkMenu::name_cb(Fl_Widget *w, void *v) {
  MaterialFltkMenu *self = (MaterialFltkMenu *)v;
  MaterialList *mlist = self->app->materialList;
  if (!self->app->material_rename(mlist->material_name(self->curmat), 
        ((Fl_Input *)w)->value())) {
    // command failed; reset the name to its original value
    self->nameinput->value(
        self->app->materialList->material_name(self->curmat));
  }
}
  
MaterialFltkMenu::MaterialFltkMenu(VMDApp *vmdapp)
: VMDFltkMenu("material", "Materials", vmdapp) {

  init();
  command_wanted(Command::MATERIAL_RENAME);
  command_wanted(Command::MATERIAL_CHANGE);
  command_wanted(Command::MATERIAL_ADD);
  command_wanted(Command::MATERIAL_DELETE);
  command_wanted(Command::MATERIAL_DEFAULT);

  curmat = 0;
  fill_material_browser();
  set_sliders();
}

void MaterialFltkMenu::init() {
  size(270,405);
  {
    { browser = new Fl_Hold_Browser(10, 10, 145, 130);
      VMDFLTKTOOLTIP(browser, "Select material to edit")
      browser->color(VMDMENU_BROWSER_BG);
      browser->selection_color(VMDMENU_BROWSER_SEL);
      browser->callback(browser_cb, this);
    }
    Fl_Button *b = new Fl_Button(165, 10, 95, 25, "Create New");
#if defined(VMDMENU_WINDOW)
    b->color(VMDMENU_WINDOW, FL_GRAY);
#endif
    VMDFLTKTOOLTIP(b, "Create a new copy of the selected material")
    b->callback(createnew_cb, this);

    deletebutton = new Fl_Button(165, 35, 95, 25, "Delete");
#if defined(VMDMENU_WINDOW)
    deletebutton->color(VMDMENU_WINDOW, FL_GRAY);
#endif
    VMDFLTKTOOLTIP(deletebutton, "Delete the selected material")
    deletebutton->callback(delete_cb, this);

    defaultbutton = new Fl_Button(165, 60, 95, 25, "Default");
#if defined(VMDMENU_WINDOW)
    defaultbutton->color(VMDMENU_WINDOW, FL_GRAY);
#endif
    VMDFLTKTOOLTIP(defaultbutton, "Reset built-in materials to defaults")
    defaultbutton->callback(default_cb, this);
 
    { nameinput = new Fl_Input(165, 115, 95, 25);
      VMDFLTKTOOLTIP(nameinput, "Rename this material")
      nameinput->color(VMDMENU_VALUE_BG, VMDMENU_VALUE_SEL);
      nameinput->when(FL_WHEN_ENTER_KEY);
      nameinput->callback(name_cb, this);
    }
    { Fl_Value_Slider* o = ambient = new Fl_Value_Slider(10, 160, 170, 20, "Ambient");
      VMDFLTKTOOLTIP(o, "Affects how dark the darkest object/shadow can be")
      o->type(FL_HORIZONTAL);
      o->color(VMDMENU_MATSLIDER_BG, VMDMENU_MATSLIDER_FG);
      o->align(FL_ALIGN_RIGHT);
      o->callback(slider_cb, this);
    }
    { Fl_Value_Slider* o = diffuse = new Fl_Value_Slider(10, 185, 170, 20, "Diffuse");
      VMDFLTKTOOLTIP(o, "Diffuse reflectance (paper, dull wood)")
      o->type(FL_HORIZONTAL);
      o->color(VMDMENU_MATSLIDER_BG, VMDMENU_MATSLIDER_FG);
      o->align(FL_ALIGN_RIGHT);
      o->callback(slider_cb, this);
    }
    { Fl_Value_Slider* o = specular = new Fl_Value_Slider(10, 210, 170, 20, "Specular");
      VMDFLTKTOOLTIP(o, "Specular reflectance (glass, glossy materials)")
      o->type(FL_HORIZONTAL);
      o->color(VMDMENU_MATSLIDER_BG, VMDMENU_MATSLIDER_FG);
      o->align(FL_ALIGN_RIGHT);
      o->callback(slider_cb, this);
    }
    { Fl_Value_Slider* o = shininess = new Fl_Value_Slider(10, 235, 170, 20, "Shininess");
      VMDFLTKTOOLTIP(o, "Degree of shininess (size of specular highlight is smaller as shininess is increased)")
      o->type(FL_HORIZONTAL);
      o->color(VMDMENU_MATSLIDER_BG, VMDMENU_MATSLIDER_FG);
      o->align(FL_ALIGN_RIGHT);
      o->callback(slider_cb, this);
    }
    { Fl_Value_Slider* o = mirror = new Fl_Value_Slider(10, 260, 170, 20, "Mirror");
      VMDFLTKTOOLTIP(o, "Mirror reflection (ray tracing only)")
      o->type(FL_HORIZONTAL);
      o->color(VMDMENU_MATSLIDER_BG, VMDMENU_MATSLIDER_FG);
      o->align(FL_ALIGN_RIGHT);
      o->callback(slider_cb, this);
    }
    { Fl_Value_Slider* o = opacity = new Fl_Value_Slider(10, 285, 170, 20, "Opacity");
      VMDFLTKTOOLTIP(o, "Degree of opacity (1.0 - transparency)")
      o->type(FL_HORIZONTAL);
      o->color(VMDMENU_MATSLIDER_BG, VMDMENU_MATSLIDER_FG);
      o->align(FL_ALIGN_RIGHT);
      o->callback(slider_cb, this);
    }
    { Fl_Value_Slider* o = outline = new Fl_Value_Slider(10, 310, 170, 20, "Outline");
      VMDFLTKTOOLTIP(o, "Outline shading saturation")
      o->type(FL_HORIZONTAL);
      o->range(0.0, 4.0); // allow a much larger range of values
      o->color(VMDMENU_MATSLIDER_BG, VMDMENU_MATSLIDER_FG);
      o->align(FL_ALIGN_RIGHT);
      o->callback(slider_cb, this);
    }
    { Fl_Value_Slider* o = outlinewidth = new Fl_Value_Slider(10, 335, 170, 20, "OutlineWidth");
      VMDFLTKTOOLTIP(o, "Width/breadth of outline shading effect")
      o->type(FL_HORIZONTAL);
      o->color(VMDMENU_MATSLIDER_BG, VMDMENU_MATSLIDER_FG);
      o->align(FL_ALIGN_RIGHT);
      o->callback(slider_cb, this);
    }
    {
      Fl_Check_Button * o = transmode = new Fl_Check_Button(10, 360, 270, 25, "Angle-Modulated Transparency");
      VMDFLTKTOOLTIP(o, "Enable angle modulated transparency (edge-on is more opaque)")
      o->callback(slider_cb, this);
    }
    end();
  }
}

void MaterialFltkMenu::fill_material_browser() {
  // Get the material names from the MaterialList and post them
  MaterialList *mlist = app->materialList;
  browser->clear();
  for (int j=0; j<mlist->num(); j++)
    browser->add(mlist->material_name(j));
  browser->select(curmat+1);
}

void MaterialFltkMenu::set_sliders() {
  // Set the values to those of the currently highlighted material 
  MaterialList *mlist = app->materialList;
  ambient->value(mlist->get_ambient(curmat));
  specular->value(mlist->get_specular(curmat));
  diffuse->value(mlist->get_diffuse(curmat));
  shininess->value(mlist->get_shininess(curmat));
  mirror->value(mlist->get_mirror(curmat));
  opacity->value(mlist->get_opacity(curmat));
  outline->value(mlist->get_outline(curmat));
  outlinewidth->value(mlist->get_outlinewidth(curmat));
  transmode->value((int) mlist->get_transmode(curmat));
  nameinput->value(mlist->material_name(curmat));

  if (curmat == 0 || curmat == 1) {
    deletebutton->deactivate();
    nameinput->deactivate();
    defaultbutton->activate();
  } else {
    deletebutton->activate();
    nameinput->activate();
    defaultbutton->deactivate();
  }
}

int MaterialFltkMenu::act_on_command(int type, Command *cmd) {
  switch (type) {
    case Command::MATERIAL_ADD:
    case Command::MATERIAL_DELETE:
      fill_material_browser();
      browser->select(browser->size());
      curmat = browser->size()-1;
      set_sliders();
      break;
    case Command::MATERIAL_RENAME:
      fill_material_browser();
      nameinput->value(app->materialList->material_name(curmat));
      break;
    case Command::MATERIAL_CHANGE:
    case Command::MATERIAL_DEFAULT:
      set_sliders();
      break;
  }
  return 0;
}
 
